#ifndef __FORMAT_H__
#define __FORMAT_H__

#include <iostream>
#include <memory>
#include <time.h>
#include <vector>
#include <sstream>
#include <assert.h>

#include "message.hpp"

// 日志格式化类

namespace log_p
{
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void format(std::ostream &out, const message &log_message) = 0;
    };

    // 派生类：获取各自的数据类型
    class LevelFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override
        {
            out << log_p::log_level::log_tostring(log_message._log_level);
        }
    };

    class BodyFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override
        {
            out << log_message._message_body;
        }
    };

    class F_nameFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override { out << log_message._file_name; }
    };

    class F_lineFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override { out << log_message._file_line; }
    };

    class Th_idFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override { out << log_message._thread_id; }
    };

    class Log_MethodFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override { out << log_message._log_method; }
    };

    class TabFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override { out << " "; }
    };

    class TimeFormat : public FormatItem
    {
    public:
        TimeFormat(const std::string st = "%H%M%S") // 默认时间格式化规则，时，分，秒
            : _time_format(st)
        {
        }

        virtual void format(std::ostream &out, const message &log_message) override
        {
            // 获取时间格式 localtime, strtime
            struct tm t;
            localtime_r(&log_message._time, &t);
            char str_time[32] = {0};
            strftime(str_time, 31, "%H:%M:%S", &t);
            out << str_time;
        }

    private:
        std::string _time_format;
    };

    class New_lineFormat : public FormatItem
    {
    public:
        virtual void format(std::ostream &out, const message &log_message) override { out << std::endl; }
    };

    class OtherFormat : public FormatItem
    {
    public:
        OtherFormat(const std::string str) : _str(str) {}

        virtual void format(std::ostream &out, const message &log_message) override
        {
            out << _str;
        }

    private:
        std::string _str;
    };

    /*
        %d 表示时间，后面包含子项{%H:%M:%S}
        %t 表示线程id
        %c 表示日志器名称
        %f 表示源文件名
        %l 表示源文件行
        %p 表示日志级别
        %T 表示制表符缩进
        %m 表示主体信息
        %n 表示换行
    */

    // 功能：对日志格式化解析，并调用创建的对象
    class Formatter
    {
    public:
        using ptr = std::shared_ptr<Formatter>;

        // {%H:%M:%S}
        Formatter(const std::string log_format = "[%d][%p]%T%m%T[%f][%l][%c][%t]%n")
            : _str_format(log_format) { assert(parse_pattern()); }
        // 从字节流中获取已经排列好的日志信息
        std::string GetResult(const message &logMsg)
        {
            std::stringstream ss;
            format(ss, logMsg);
            return ss.str();
        }

    private:
        // 根据不同的标记号构建不同的格式化子项对象
        FormatItem::ptr create_format_item(const std::string &key, const std::string &val)
        {
            // if ( key == "d")  return std::shared_ptr<TimeFormat>(new TimeFormat(val));
            if (key == "d")
                return std::make_shared<TimeFormat>(val);
            if (key == "t")
                return std::make_shared<Th_idFormat>();
            if (key == "c")
                return std::make_shared<Log_MethodFormat>();
            if (key == "f")
                return std::make_shared<F_nameFormat>();
            if (key == "l")
                return std::make_shared<F_lineFormat>();
            if (key == "p")
                return std::make_shared<LevelFormat>();
            if (key == "T")
                return std::make_shared<TabFormat>();
            if (key == "m")
                return std::make_shared<BodyFormat>();
            return FormatItem::ptr(new BodyFormat());
            if (key == "n")
                return std::make_shared<New_lineFormat>();
            return std::make_shared<OtherFormat>(val);
        }

        // 解析形成日志格式
        bool parse_pattern()
        {
            size_t ptr = 0;
            size_t cur = 0;
            while (cur < _str_format.size())
            {
                if (_str_format.compare(cur, 1, "%") == 0)
                {
                    // 找到 %后，只要cur > ptr说明前面有正文, 将前文载入
                    if (cur > ptr)
                    {
                        auto it = create_format_item("%", _str_format.substr(ptr, cur - ptr));
                        _items.push_back(it);
                        ptr = cur;
                    }

                    if (_str_format.compare(cur + 1, 1, "%") == 0) // 异常的连续%
                    {
                        cur++;
                        continue;
                    }
                    else // 正常% + 字母
                    {
                        auto it = create_format_item({_str_format[cur + 1]}, _str_format.substr(cur, 2));
                        _items.push_back(it);
                        cur += 2;
                        ptr = cur;
                        continue;
                    }
                }
                cur++;
            }

            if (cur != ptr)
            {
                auto it = create_format_item("%", _str_format.substr(ptr, cur - ptr));
                _items.push_back(it);
                ptr = cur;
            }

            return true;
        }

        // 日志构造流水线
        void format(std::ostream &out, const message &logMsg)
        {
            for (auto &item : _items)
            {
                item->format(out, logMsg);
            }
        }

    private:
        std::string _str_format;             // 日志格式化规则信息
        std::vector<FormatItem::ptr> _items; // 对设置的日志信息分成一段段，每一段进行创建对象，并统一调用对象函数处理结果

        std::mutex _items_mutex;
    };

}

#endif